"""
MQTT命令发布模块
"""
import json
import time
import uuid
from typing import Dict, Any, Optional, Callable

from common.config import settings
from common.logger import create_logger


class CommandPublisher:
    def __init__(self):
        self.logger = create_logger("mqtt_publisher", settings.log_level, settings.log_file)
        self.pending_commands: Dict[str, Dict] = {}  # 存储等待响应的命令
        self.setup_mqtt_client()

    def setup_mqtt_client(self):
        """设置MQTT客户端并连接"""
        # 这里可以使用您现有的MQTTClient类，但需要添加发布功能
        # 或者创建一个专用的发布客户端
        try:
            import paho.mqtt.client as mqtt

            self.client = mqtt.Client(
                client_id=f"command_publisher_{uuid.uuid4().hex[:8]}",
                clean_session=True
            )

            # 设置回调
            self.client.on_connect = self._on_connect
            self.client.on_message = self._on_message

            # 认证设置
            if settings.mqtt_user and settings.mqtt_password:
                self.client.username_pw_set(settings.mqtt_user, settings.mqtt_password)

            # 连接Broker
            self.client.connect(settings.mqtt_broker, settings.mqtt_port, 60)
            self.client.loop_start()

            # 订阅响应主题
            response_topic = f"{settings.mqtt_response_topic_prefix}/#"
            self.client.subscribe(response_topic, qos=1)
            self.logger.info(f"Subscribed to response topic: {response_topic}")

        except Exception as e:
            self.logger.error(f"Failed to setup MQTT client: {str(e)}")
            raise

    def _on_connect(self, client, userdata, flags, rc):
        """连接回调"""
        if rc == 0:
            self.logger.info("Connected to MQTT broker for command publishing")
        else:
            self.logger.error(f"Failed to connect to MQTT broker: {rc}")

    def _on_message(self, client, userdata, msg):
        """消息回调（处理设备响应）"""
        try:
            payload = msg.payload.decode()
            self.logger.debug(f"Received response on {msg.topic}: {payload}")

            # 解析响应消息
            response_data = json.loads(payload)
            command_id = response_data.get("command_id")

            # 查找对应的等待中的命令
            if command_id in self.pending_commands:
                pending_command = self.pending_commands[command_id]
                pending_command["response"] = response_data
                pending_command["event"].set()  # 通知等待线程

        except Exception as e:
            self.logger.error(f"Error processing response: {str(e)}")

    def send_command(self, device_id: str, command: str,
                     params: Optional[Dict] = None,
                     timeout: Optional[int] = None) -> Dict[str, Any]:
        """
        向设备发送命令并等待响应

        Args:
            device_id: 设备ID
            command: 命令类型
            params: 命令参数
            timeout: 超时时间（秒）

        Returns:
            设备响应数据
        """
        if timeout is None:
            timeout = settings.command_timeout

        # 生成唯一命令ID
        command_id = str(uuid.uuid4())

        # 构建命令消息
        command_msg = {
            "command_id": command_id,
            "command": command,
            "timestamp": int(time.time()),
            "params": params or {}
        }

        # 准备等待事件
        import threading
        event = threading.Event()
        self.pending_commands[command_id] = {
            "event": event,
            "response": None
        }

        try:
            # 发布命令
            topic = f"{settings.mqtt_command_topic_prefix}/{device_id}"
            self.client.publish(topic, json.dumps(command_msg), qos=1)
            self.logger.info(f"Sent command to {topic}: {command}")

            # 等待响应
            if event.wait(timeout):
                response = self.pending_commands[command_id]["response"]
                return response
            else:
                raise TimeoutError(f"Command timeout after {timeout} seconds")

        finally:
            # 清理
            if command_id in self.pending_commands:
                del self.pending_commands[command_id]

    def send_command_async(self, device_id: str, command: str,
                           params: Optional[Dict] = None,
                           callback: Optional[Callable] = None):
        """
        异步发送命令（不等待响应）
        """
        # 生成唯一命令ID
        command_id = str(uuid.uuid4())

        # 构建命令消息
        command_msg = {
            "command_id": command_id,
            "command": command,
            "timestamp": int(time.time()),
            "params": params or {}
        }

        # 如果需要回调，注册回调
        if callback:
            self.pending_commands[command_id] = {
                "callback": callback,
                "timestamp": time.time()
            }

        # 发布命令
        topic = f"{settings.mqtt_command_topic_prefix}/{device_id}"
        self.client.publish(topic, json.dumps(command_msg), qos=1)
        self.logger.info(f"Sent async command to {topic}: {command}")

        return command_id

    def cleanup(self):
        """清理资源"""
        if hasattr(self, 'client'):
            self.client.loop_stop()
            self.client.disconnect()
            self.logger.info("Command publisher disconnected")


# 全局命令发布器实例
command_publisher = CommandPublisher()


def get_command_publisher():
    """获取命令发布器实例"""
    return command_publisher
